package com.buaa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.buaa.config.MapConfig;
import com.buaa.dto.MapStoreDTO;
import com.buaa.dto.MapUpdateDTO;
import com.buaa.entity.Address;
import com.buaa.entity.Maps;
import com.buaa.mapper.AddressMapper;
import com.buaa.mapper.MapsMapper;
import com.buaa.service.IMapsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.buaa.vo.maps.MapsVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 地图数据表 服务实现类
 * </p>
 *
 * @author baomidou
 * @since 2024-06-12
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MapsServiceImpl extends ServiceImpl<MapsMapper, Maps> implements IMapsService {

    private final MapConfig mapConfig;

    private final AddressMapper addressMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void store(MapStoreDTO mapStoreDTO) {
        Maps province = lambdaQuery().eq(Maps::getName, mapStoreDTO.getProvince()).one();
        if (mapStoreDTO.getDistrict().isEmpty() && mapStoreDTO.getCity().isEmpty() && province != null) {
            throw new RuntimeException("该省数据已存在");
        }
        Maps map = new Maps();
        map.setAdcode(mapStoreDTO.getAdcode());
        map.setGeo(mapStoreDTO.getGeo());
        map.setPinyin(mapStoreDTO.getPinyin());

        Address address = new Address();
        address.setAdcode(mapStoreDTO.getAdcode());

        if (!mapStoreDTO.getDistrict().isEmpty() && !mapStoreDTO.getCity().isEmpty() && !mapStoreDTO.getProvince().isEmpty()) {
            if (province == null) {
                throw new RuntimeException("省地图的数据未存储");
            }
            // 添加区县地图
            Maps city;
            if (mapConfig.getDirectCities().contains(mapStoreDTO.getProvince())) {
                // 直辖市
                city = province;
            } else {
                city = lambdaQuery().eq(Maps::getPid, province.getId()).eq(Maps::getName, mapStoreDTO.getCity()).one();
            }
            QueryWrapper<Address> addressQueryWrapper = new QueryWrapper<>();
            addressQueryWrapper.eq("name",mapStoreDTO.getCity()).eq("level","city");
            Address cityAddress = addressMapper.selectOne(addressQueryWrapper);
            if (city == null || cityAddress == null) {
                throw new RuntimeException("您传入的市有误");
            }
            map.setPid(city.getId());
            map.setName(mapStoreDTO.getDistrict());
            save(map);

            address.setPid(cityAddress.getId());
            address.setLevel("district");
            address.setName(mapStoreDTO.getDistrict());
            address.setMapId(map.getId());
            int i = addressMapper.insert(address);
            if (i <= 0) {
                throw new RuntimeException("数据添加失败");
            }
        } else if (!mapStoreDTO.getCity().isEmpty() && !mapStoreDTO.getProvince().isEmpty()) {
            if (mapConfig.getDirectCities().contains(mapStoreDTO.getCity())) {
                // 直辖市按省处理
                storeProvince(mapStoreDTO,map,address);
            } else {
                // 不是直辖市存储地图
                // 添加市的地图
                if (province == null) {
                    throw new RuntimeException("省地图的数据未存储");
                }
                QueryWrapper<Address> addressQueryWrapper = new QueryWrapper<>();
                addressQueryWrapper.eq("name",mapStoreDTO.getProvince());
                Address provinceAddress = addressMapper.selectOne(addressQueryWrapper);
                if (provinceAddress == null) {
                    throw new RuntimeException("省不存在");
                }

                map.setPid(province.getId());
                map.setName(mapStoreDTO.getCity());
                save(map);

                address.setPid(provinceAddress.getId());
                address.setLevel("city");
                address.setName(mapStoreDTO.getCity());
                address.setMapId(map.getId());
                int i = addressMapper.insert(address);
                if (i <= 0) {
                    throw new RuntimeException("数据添加失败");
                }
            }
        } else {
            storeProvince(mapStoreDTO, map, address);
        }
    }

    private void storeProvince(MapStoreDTO mapStoreDTO,Maps map,Address address) {
        map.setPid(0);
        map.setName(mapStoreDTO.getProvince());
        save(map);

        storeDirectCity(mapStoreDTO.getProvince(),address,map);
    }

    /**
     * Address存储直辖市时，省市一起添加
     * @param cityName
     * @param address
     */
    private void storeDirectCity(String cityName, Address address, Maps map) {
        address.setPid(0);
        address.setName(cityName);
        address.setLevel("province");
        address.setMapId(map.getId());
        int i = addressMapper.insert(address);
        if (i <= 0) {
            throw new RuntimeException("省添加失败");
        }

        if (mapConfig.getDirectCities().contains(cityName)) {
            // 直辖市
            // 地址库再存一条市级数据
            Address city = BeanUtil.toBean(address, Address.class);
            city.setId(null);
            city.setPid(address.getId());
            city.setLevel("city");
            city.setMapId(map.getId());
            int ci = addressMapper.insert(city);
            if (ci <= 0) {
                throw new RuntimeException("市添加失败");
            }
        }
    }

    @Override
    public List<MapsVO> getMapsByPid(Integer pid) {
        List<Maps> list = lambdaQuery().eq(Maps::getPid, pid).list();
        return BeanUtil.copyToList(list, MapsVO.class);
    }

    /**
     * 更新数据，更新时不考虑父子级的更新，父子级不可更改
     * @param mapUpdateDTO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMaps(MapUpdateDTO mapUpdateDTO) {
        Address address = addressMapper.selectById(mapUpdateDTO.getId());
        // 如果是直辖市，省市都要改，查询多个保险一点
        List<Address> addresses = addressMapper.selectList(new LambdaQueryWrapper<Address>().eq(Address::getAdcode, address.getAdcode()));
        addresses.forEach(v -> {
            Address updateAddress = new Address();
            updateAddress.setId(v.getId());
            updateAddress.setName(mapUpdateDTO.getName());
            updateAddress.setAdcode(mapUpdateDTO.getAdcode());
            addressMapper.updateById(updateAddress);
        });

        Maps updateMap = new Maps();
        updateMap.setId(addresses.get(0).getMapId());
        updateMap.setAdcode(mapUpdateDTO.getAdcode());
        updateMap.setName(mapUpdateDTO.getName());
        updateMap.setPinyin(mapUpdateDTO.getPinyin());
        updateMap.setGeo(mapUpdateDTO.getGeo());
        updateById(updateMap);
    }
}
